package com.bupt.Factory;

import com.bupt.annotation.MParam;
import com.bupt.basic.IBasicNetWork;
import com.bupt.dto.network.Node;
import com.bupt.exception.BaseException;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.io.*;
import java.util.*;

public class ProjectResultCenter {


    // 文件的后缀
    private static final String FILE_SUFFIX = ".result";


    /// 获取文件存储位置
    private static String getRelativeFilePath() {
        // 返回文件的存储位置
        return ProjectFactory.storePath + File.separator + "plan_result";
    }


    //存储规划的结果
    public static boolean savePlanResultToFile(@MParam("规划结果") PlanResultData planResultData,
                                               @MParam("项目ID") String dataId) throws BaseException {


        File file = new File(getRelativeFilePath(), dataId + FILE_SUFFIX);
        if (file.exists()) {
            boolean res = file.delete();
            // 删除存在的文件
        }

        ObjectOutputStream oos = null;
        try {
            oos = new ObjectOutputStream(new FileOutputStream(file));
            oos.writeObject(planResultData);
            return true;
        } catch (Exception e) {
            throw new BaseException(e.getMessage());
        } finally {
            if (null != oos) {
                try {
                    oos.close();
                } catch (IOException e) {
                    throw new BaseException("文件操作异常");
                }
            }
        }
    }

    // 获取到规划的结果
    public static PlanResultData getPlanResultFromFile(@MParam("数据的ID") String dataId) throws BaseException {
        if (null == dataId || "".equals(dataId)) {
            return null;
        }
        // 文件夹
        File director = new File(getRelativeFilePath());
        if (!director.exists()) {
            return null;
        }
        // 获取文件的名字
        File file = new File(getRelativeFilePath(), dataId + FILE_SUFFIX);
        if (!file.exists()) {
            return null;
        }
        ObjectInputStream ios = null;
        try {
            ios = new ObjectInputStream(new FileInputStream(file));
            return (PlanResultData) ios.readObject();
        } catch (Exception e) {
            // throw
            throw new BaseException("获取对象失败");

        } finally {
            if (null != ios) {
                try {
                    ios.close();
                } catch (IOException e) {
                    throw new BaseException("操作文件异常");
                }
            }
        }
    }

    //清除相应业务的规划结果，用于修改业务信息后的展示
    public static boolean clearRelatedServices(String dataId, List<String> serviceIds) throws BaseException {
        PlanResultData resultData = getPlanResultFromFile(dataId);
        if (resultData == null) throw new BaseException("不存在相应规划结果:" + dataId + ".result");
        if (serviceIds == null) throw new BaseException("未修改任何业务");
        for (String serviceId : serviceIds) {
            resultData.workRoute.remove(serviceId);
            resultData.protectRoute.remove(serviceId);
            resultData.planStatus.put(serviceId, "fault");
            resultData.planReason.put(serviceId, "未规划");
        }

        if (savePlanResultToFile(resultData,dataId)) {
            return true;
        } else {
            return false;
        }
    }

    //规划结果的结构
    @EqualsAndHashCode
    @Data
    public static class PlanResultData implements Serializable {
        private static final long serialVersionUID = 7384428030693089003L;
        private String dataId;

        //项目各业务上的路由信息
       public Map<String, RouteType> workRoute = new HashMap<>();
       public Map<String, RouteType> protectRoute = new HashMap<>();

        //项目各业务的规划成功与否信息,<serviceId,status> 而status为"success"或"error"
       public Map<String, String> planStatus = new HashMap<>();

        //记录每一次规划各业务的原因<serviceId,reason>
       public Map<String, String> planReason = new HashMap<>();

        //项目各链路上的业务信息
       public Map<String, LinkMsg> linkMsg = new HashMap<>();
       //端口信息
        public  Map<String,List<IBasicNetWork.PortL>> portsMap=new HashMap<>();

        public PlanResultData(String dataId, Map<String, RouteType> workRoute, Map<String, RouteType> protectRoute, Map<String, LinkMsg> linkMsg,
                              Map<String, String> planStatus, Map<String, String> planReason,Map<String,List<IBasicNetWork.PortL>> portsMap) {
            this.dataId = dataId;
            this.workRoute = workRoute;
            this.protectRoute = protectRoute;
            this.linkMsg = linkMsg;
            this.planStatus = planStatus;
            this.planReason = planReason;
            this.portsMap=portsMap;
        }
    }

    @Data
    public static class RouteType implements Serializable {
        private List<RouteNodeType> nodeList = new ArrayList<>();
        private List<RouteLinkType> linklist = new ArrayList<>();

        public RouteType(List<RouteNodeType> nodeList, List<RouteLinkType> linklist) {
            this.nodeList = nodeList;
            this.linklist = linklist;
        }
    }

    @Data
    public static class RouteNodeType implements Serializable {
        private String id;
        private String name;
        private double longitude;
        private double latitude;

        public RouteNodeType(String id, String name, double longitude, double latitude) {
            this.id = id;
            this.name = name;
            this.longitude = longitude;
            this.latitude = latitude;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            RouteNodeType that = (RouteNodeType) o;
            return Objects.equals(id, that.id) &&
                    Objects.equals(name, that.name);
        }

        @Override
        public int hashCode() {
            return Objects.hash(id, name);
        }
    }

    @Data
    public static class RouteLinkType implements Serializable {
        private String id;
        private String name;
        private String type;
        private RouteNodeType sourceNode;
        private RouteNodeType targetNode;

        public RouteLinkType(String id, String name, String type,
                             Node sourceNode1, Node targetNode1) {
            this.id = id;
            this.name = name;
            this.type = type;
            this.sourceNode = new RouteNodeType(sourceNode1.getId(),sourceNode1.getName(),
                    sourceNode1.getLongitude(),sourceNode1.getLatitude());
            this.targetNode =new RouteNodeType(targetNode1.getId(),targetNode1.getName(),
                    targetNode1.getLongitude(),targetNode1.getLatitude());
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            RouteLinkType that = (RouteLinkType) o;
            return Objects.equals(id, that.id) &&
                    Objects.equals(name, that.name) &&
                    Objects.equals(type, that.type);
        }

        @Override
        public int hashCode() {
            return Objects.hash(id, name, type);
        }
    }

    // 链路上的业务信息
    @Data
    public static class LinkMsg implements Serializable {
        private String linkId;
        private String linkName;
        private String linkType;
        private Set<String> serviceIdSet = new HashSet<>();

        //private List<String> waveLengthService = new ArrayList<>();  //zldService.get(i)表示第i个子粒度下承载的业务id
        public LinkMsg(String linkId, String linkName, String linkType) {
            this.linkId = linkId;
            this.linkName = linkName;
            this.linkType = linkType;
        }
    }
}
